﻿// Inner Fire 游戏引擎库
// 游戏时间类
//
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 这个类用于管理游戏时间与帧数。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-15

#include "timer.h"
#include <stdio.h>
#include <windows.h>

namespace ifire {

// 用于全局的快速读取
Timer g_timer;

Timer::Timer()
    : seconds_per_count_(0.0)
    , delta_time_(-1.0)
    , base_time_(0)
    , paused_time_(0)
    , prev_time_(0)
    , current_time_(0)
    , stop_time_(0)
    , is_stopped_(false)
    , frame_remain_(DEFAULT_FRAME_TIME)
    , fixedDeltaTime(0.0f)
    , last_frame_tick_(0.0f) {
  __int64 countsPerSec;
  QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
  seconds_per_count_ = 1.0 / (double)countsPerSec;
  memset(fps_text, 0, sizeof(fps_text));
}

// Returns the total time elapsed since Reset() was called, NOT counting any
// time when the clock is stopped.
float Timer::TotalTime() const {
  // If we are stopped, do not count the time that has passed since we stopped.
  // Moreover, if we previously already had a pause, the distance
  // mStopTime - mBaseTime includes paused time, which we do not want to count.
  // To correct this, we can subtract the paused time from mStopTime:
  //
  //                     |<--paused time-->|
  // ----*---------------*-----------------*------------*------------*------>
  // time
  //  mBaseTime       mStopTime        startTime     mStopTime    mCurrTime

  if (is_stopped_) {
    return (
        float)(((stop_time_ - paused_time_) - base_time_) * seconds_per_count_);
  }

  // The distance mCurrTime - mBaseTime includes paused time,
  // which we do not want to count.  To correct this, we can subtract
  // the paused time from mCurrTime:
  //
  //  (mCurrTime - mPausedTime) - mBaseTime
  //
  //                     |<--paused time-->|
  // ----*---------------*-----------------*------------*------> time
  //  mBaseTime       mStopTime        startTime     mCurrTime

  else {
    return (float)(((current_time_ - paused_time_) - base_time_) *
                   seconds_per_count_);
  }
}

float Timer::DeltaTime() const { return (float)delta_time_; }

bool Timer::CheckFixedUpdate() {
  if (frame_remain_ > 0.0f) {
    return false;
  }

  // 这里不使用直接等于，是因为存在一定误差，这个误差要计算进去。
  frame_remain_ += DEFAULT_FRAME_TIME;

  // 进行检查
  if (frame_remain_ < 0.0f) {
    frame_remain_ = 0.0f;
  } else if (frame_remain_ > DEFAULT_FRAME_TIME) { // 这个理论上是永不发生的。
    frame_remain_ = DEFAULT_FRAME_TIME;
  }

  // 得到时间的差值。但时间差值也不能大于一定数量
  constexpr float BARRIER = DEFAULT_FRAME_TIME * 100.0f;
  auto current_seconds = (current_time_)*seconds_per_count_;

  // 这个虽然不准确，但是因为和它奇怪的东西混用，所以只好这样了。暂时用着。
  fixedDeltaTime = DEFAULT_FRAME_TIME;
  // min(current_seconds - last_frame_tick_, BARRIER);

  last_frame_tick_ = current_seconds;

  return true;
}

void Timer::Reset() {
  __int64 currTime;
  QueryPerformanceCounter((LARGE_INTEGER*)&currTime);

  base_time_ = currTime;
  prev_time_ = currTime;
  last_frame_tick_ = currTime * seconds_per_count_;
  stop_time_ = 0;
  is_stopped_ = false;
}

void Timer::Start() {
  __int64 startTime;
  QueryPerformanceCounter((LARGE_INTEGER*)&startTime);

  // Accumulate the time elapsed between stop and start pairs.
  //
  //                     |<-------d------->|
  // ----*---------------*-----------------*------------> time
  //  mBaseTime       mStopTime        startTime

  if (is_stopped_) {
    paused_time_ += (startTime - stop_time_);

    prev_time_ = startTime;
    stop_time_ = 0;
    is_stopped_ = false;
  }
}

void Timer::Stop() {
  if (!is_stopped_) {
    __int64 currTime;
    QueryPerformanceCounter((LARGE_INTEGER*)&currTime);

    stop_time_ = currTime;
    is_stopped_ = true;
  }
}

void Timer::Tick() {
  if (is_stopped_) {
    delta_time_ = 0.0;
    return;
  }

  __int64 currTime;
  QueryPerformanceCounter((LARGE_INTEGER*)&currTime);
  current_time_ = currTime;

  // Time difference between this frame and the previous.
  delta_time_ = (current_time_ - prev_time_) * seconds_per_count_;

  // Prepare for next frame.
  prev_time_ = current_time_;

  // Force nonnegative.  The DXSDK's CDXUTTimer mentions that if the
  // processor goes into a power save mode or we get shuffled to another
  // processor, then mDeltaTime can be negative.
  if (delta_time_ < 0.0) {
    delta_time_ = 0.0;
  }
  // 设置属性
  deltaTime = delta_time_;

  // 减去每帧的时间
  frame_remain_ -= delta_time_;
}

void Timer::CalculateFps() {
  frame_count_++;
  auto total_time = TotalTime();
  if (total_time - time_elapsed >= 1.0f) {
    fps_ = static_cast<float>(frame_count_);
    frame_count_ = 0;
    time_elapsed += 1.0f;
  }
}

const char* Timer::GetFpsFormat(const char* format) {
  sprintf(fps_text, format, fps_);
  return fps_text;
}

} // namespace ifire